package per.sunmes.lesrb.manager;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.compression.Lzma;

import per.sunmes.lesrb.apis.Config;
import per.sunmes.lesrb.apis.ConfigLoader;
import per.sunmes.lesrb.util.GM;

/**
 * ConfigManager.
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class CM {
	private static final String TAG = "ConfigManager:CM";
	public static final byte[] UTF8BOM = new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };

	public static boolean isReadEncode = false;
	public static boolean isLogOutConfigData = false;

	public static ConfigLoader defaultEncodeLoader = new ConfigLoader() {

		@Override
		public InputStream getFileInputStream(FileHandle file) throws IOException {
			// 加密模式,输出文件就需要去掉BOM.这里不需要判断BOM
			InputStream input = file.read();
			InputStream retInput = null;
			try {
				ByteArrayOutputStream bout = new ByteArrayOutputStream();
				Lzma.decompress(input, bout);
				retInput = new ByteArrayInputStream(bout.toByteArray());
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				input.close();
			}
			return retInput;
		}

	};

	public static ConfigLoader defaultNoEncodeLoader = new ConfigLoader() {
		@Override
		public InputStream getFileInputStream(FileHandle file) throws IOException {
			InputStream input = file.read();

			// EF BB BF 文本文件需要判断BOM
			boolean isHasBom = true;
			byte[] bomCheck = new byte[UTF8BOM.length];
			input.read(bomCheck, 0, bomCheck.length);
			for (int i = 0; i < UTF8BOM.length; i++) {
				if (bomCheck[i] != UTF8BOM[i]) {
					isHasBom = false;
					break;
				}
			}
			if (!isHasBom) {
				input.close();
				input = file.read();
			} else {
				if (isLogOutConfigData) {
					GM.logger.log(TAG, "[" + file.name() + "]获取到Bom头,舍弃BOM字节.");
				}
			}
			return input;
		}
	};
	/////////
	private static CM _i;

	private static CM I() {
		if (_i == null) {
			_i = new CM();
		}
		return _i;
	}

	public static void dispose() {
		if (_i != null) {
			_i._dispose();
			_i = null;
		}
	}

	public static void loadConfig(Class<? extends Config> cls, String filePath) {
		I()._loadConfig(cls, filePath);
	}

	public static <T extends Config> T config(Class<T> cls, int id) {
		T config = I()._getConfig(cls, id);
		if (config == null) {
			GM.logger.error(TAG, "loadConfig faild! config[" + cls.getName() + "] ID[" + id + "] not found or loaded!");
		}
		return config;
	}

	public static <T extends Config> Map<Integer, T> configMap(Class<T> cls) {
		return I().configs.get(cls); //Map就不需要log提示了。
	}

	//////////

	private Map<Class<? extends Config>, Map> configs = new HashMap<Class<? extends Config>, Map>();

	private void _dispose() {
		configs.clear();
	}

	public <T extends Config> void _loadConfig(Class<T> cls, String filePath) {
		BufferedReader br = null;
		InputStream input = null;
		FileHandle fh;
		try {
			if (isLogOutConfigData) {
				GM.logger.log(TAG, "Load Config:" + filePath);
			}
			if (isReadEncode) {
				fh = RM.getFile(filePath + "e");
			} else {
				fh = RM.getFile(filePath);
			}

			if (isReadEncode) {
				input = defaultEncodeLoader.getFileInputStream(fh);
			} else {
				input = defaultNoEncodeLoader.getFileInputStream(fh);
			}

			if (input == null) {
				GM.logger.log(TAG, "ConfigLoader.getInputStream return null!!.");
				return;
			}

			br = new BufferedReader(new InputStreamReader(input, "UTF-8"));
			////////
			String line = br.readLine();
			if (isLogOutConfigData) {
				GM.logger.log(TAG, "Fields:");
			}
			String[] fields = line.split("\t");
			for (int i = 0; i < fields.length; i++) {
				fields[i] = fields[i].trim();
			}
			if (isLogOutConfigData) {
				GM.logger.log(TAG, Arrays.toString(fields));
			}
			if (fields.length < 2) {
				throw new IllegalArgumentException("Unknow Config!");
			}
			Map<Integer, T> save = new HashMap<Integer, T>();
			while ((line = br.readLine()) != null) {
				if (line.isEmpty()) {
					continue;
				}
				Map<String, String> map = readString(line, fields);
				T config = cls.newInstance();
				if (!config.readData(map)) {
					System.err.println("Config File Error! .." + line);
					System.err.println("ReadConfig[" + filePath + "] Error! DataLine:" + line);
				} else {
					save.put(config.getId(), config);
					if (isLogOutConfigData) {
						GM.logger.log(TAG, "ID:" + config.getId() + " : " + map);
					}
				}
			}
			configs.put(cls, save);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	private Map<String, String> readString(String line, String[] fields) {
		String[] values = line.split("\t");
		Map<String, String> data = new HashMap<String, String>();
		for (int i = 0; i < fields.length; i++) {
			if (values.length <= i) {
				data.put(fields[i], "");
			} else {
				data.put(fields[i], values[i].trim());
			}
		}
		return data;
	}

	//////////

	public <T> T _getConfig(Class<T> cls, int id) {
		if (configs.containsKey(cls)) {
			return (T) configs.get(cls).get(id);
		} else {
			throw new InvalidParameterException("没有找到配置项[" + cls.getName() + "] ID[" + id + "]");
		}
	}

}
